package com.california.pay.socket;

import com.bwton.socket.util.MathUtil;
import com.california.pay.config.CommonErrors;
import com.california.pay.exception.BusinessException;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import io.netty.channel.Channel;

import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class NettyChannelMap {
    private static AtomicInteger idx = new AtomicInteger(0);
    private static Map<String, Channel> channelMap = Maps.newConcurrentMap();
    private static List<Channel> channelList = Lists.newCopyOnWriteArrayList();
    //private static ConcurrentLinkedHashMap<String, Channel>  channelMap = new ConcurrentLinkedHashMap.Builder<String, Channel>().initialCapacity(64).build();
    private static Lock lock = new ReentrantLock(true);

    public static Map<String, Channel> getChannelHashMap() {
        return channelMap;
    }

    public static Channel getChannelByName(String name) {
        if (channelMap == null || channelMap.isEmpty()) {
            return null;
        }

        return channelMap.get(name);
    }

    public static Channel getNextChannel() {
        int index = MathUtil.getNonNegative(idx.getAndIncrement());
        int connections = channelList.size();

        for (int i = index; i < connections + index; i++) {
            Channel channel = channelList.get(i % connections);
            if (channel != null) {
                if (channel.isActive()) {
                    return channel;
                } else {
                    channel.close();
                }
            }
        }

        throw new BusinessException(CommonErrors.UNDEFINED, "getNextChannel#未找到可用的终端设备");
    }

    public static void addChannel(String name, Channel channel) {
        lock.lock();
        try {
            channelMap.put(name, channel);
            channelList.add(channel);
        } finally {
            lock.unlock();
        }

    }

    public static void removeChannelByName(String name) {
        lock.lock();
        try {
            if (channelMap.containsKey(name)) {
                Channel channel = channelMap.remove(name);
                if (channel != null){
                    channelList.remove(channel);
                }

            }
        } finally {
            lock.unlock();
        }

    }

}

